# coding: utf-8
from datetime import datetime

from flask import current_app
from flask_login import UserMixin, AnonymousUserMixin, login_manager
from werkzeug.security import generate_password_hash, check_password_hash

from exts import db


class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    default = db.Column(db.Boolean, default=False, index=True)
    permissions = db.Column(db.Integer)
    users = db.relationship('User', backref='role', lazy='dynamic')

    @staticmethod
    def insert_roles():
        roles = {
            'Editor': (Permission.WRITE_NEWS, True),
            'Exec-Editor': (Permission.WRITE_NEWS |
                            Permission.RELEASE_NEWS |
                            Permission.REARRANGE_NEWS, False),
            'Administrator': (Permission.WRITE_NEWS |
                              Permission.RELEASE_NEWS |
                              Permission.REARRANGE_NEWS |
                              Permission.FILE_MANAGE |
                              Permission.LOG_MANAGE |
                              Permission.RIGHT_MANAGE, False)
        }

        for r in roles:
            role = Role.query.filter_by(name=r).first()
            if role is None:
                role = Role(name=r)
            role.permissions = roles[r][0]
            role.default = roles[r][1]
            db.session.add(role)
        db.session.commit()


class Permission:
    WRITE_NEWS = 0x01
    RELEASE_NEWS = 0x02
    REARRANGE_NEWS = 0x04
    FILE_MANAGE = 0x08
    LOG_MANAGE = 0x10
    RIGHT_MANAGE = 0x20
    ADMINISTER = 0x3f


class User(UserMixin, db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    tel = db.Column(db.String(11), nullable=False, unique=True, index=True)
    uname = db.Column(db.String(50), nullable=False, unique=True, index=True)
    pwd = db.Column(db.String(100), nullable=False)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __init__(self, *args, **kwargs):
        super(User, self).__init__(**kwargs)
        if self.role is None:
            if self.tel == current_app.config['FLASK_TEL']:
                self.role = Role.query.filter_by(permissions=0x3f).first()
        if self.role is None:
            self.role = Role.query.filter_by(default=True).first()

        telephone = kwargs.get('tel')
        username = kwargs.get('uname')
        password = kwargs.get('pwd')

        self.tel = telephone
        self.uname = username
        self.pwd = generate_password_hash(password)

    def check_pwd(self, raw_pwd):
        res = check_password_hash(self.pwd, raw_pwd)
        return res

    def change_pwd(self, new_pwd):
        self.pwd = new_pwd

    def can(self, permissions):
        return self.role is not None and \
               (self.role.permissions & permissions) == permissions

    def is_administrator(self):
        return self.can(Permission.ADMINISTER)


class AnonymousUser(AnonymousUserMixin):
    def can(self, permissions):
        return False

    def is_administrator(self):
        return False


login_manager.anonymous_user = AnonymousUser


class News(db.Model):
    __tablename__ = 'news'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    create_time = db.Column(db.DateTime, default=datetime.now)
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    author = db.relationship('User', backref=db.backref('news'))
    checked = db.Column(db.Boolean, default=False)
